package info.wangyuan.agent.utils;

import cn.hutool.core.util.StrUtil;
import com.github.houbb.sensitive.word.bs.SensitiveWordBs;
import com.github.houbb.sensitive.word.support.check.WordChecks;
import com.github.houbb.sensitive.word.support.deny.WordDenySystem;
import com.github.houbb.sensitive.word.support.deny.WordDenys;
import com.github.houbb.sensitive.word.support.ignore.SensitiveWordCharIgnores;
import com.github.houbb.sensitive.word.support.resultcondition.WordResultConditions;
import com.github.houbb.sensitive.word.support.tag.WordTags;
import com.github.houbb.sensitive.word.support.warmup.WordWarmUps;
import info.wangyuan.agent.common.Constant.FileConstant;
import lombok.extern.slf4j.Slf4j;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.stream.Stream;

/**
 * 敏感词过滤工具（支持热更新）
 *
 * @author Albert
 * @since 2025-09-12 14:21:59
 */
@Slf4j
public class WordsFilter {

    /**
     * 默认词库文件名
     */
    private static final String DEFAULT_WORDS_FILE = "ai-sensitive-words.txt";

    /**
     * 当前过滤器实例
     */
    private static volatile SensitiveWordBs WORD_BS;

    /**
     * 读写锁，保证并发安全
     */
    private static final ReentrantReadWriteLock LOCK = new ReentrantReadWriteLock();

    static {
        reload(); // 启动时加载
    }

    private WordsFilter() {
    }

    /**
     * 检查消息是否包含敏感词
     */
    public static boolean wordsCheck(String message) {
        LOCK.readLock().lock();
        try {
            return WORD_BS.contains(message);
        } finally {
            LOCK.readLock().unlock();
        }
    }

    /**
     * 手动触发热更新（重新加载词库）
     */
    public static void reload() {
        LOCK.writeLock().lock();
        try {
            List<String> customWords = loadWordsFromFile();

            WORD_BS = SensitiveWordBs.newInstance()
                    .numCheckLen(8)
                    .ignoreCase(true)
                    .ignoreWidth(true)
                    .wordFailFast(true)
                    .ignoreRepeat(false)
                    .ignoreNumStyle(true)
                    .enableNumCheck(true)
                    .enableUrlCheck(true)
                    .enableWordCheck(true)
                    .enableIpv4Check(true)
                    .enableEmailCheck(true)
                    .ignoreChineseStyle(true)
                    .ignoreEnglishStyle(true)
                    .wordTag(WordTags.none())
                    .wordCheckUrl(WordChecks.url())
                    .wordCheckNum(WordChecks.num())
                    .wordCheckIpv4(WordChecks.ipv4())
                    .wordCheckWord(WordChecks.word())
                    .wordWarmUp(WordWarmUps.defaults())
                    .wordCheckEmail(WordChecks.email())
                    .charIgnore(SensitiveWordCharIgnores.defaults())
                    .wordResultCondition(WordResultConditions.alwaysTrue())
                    // 系统内置词典 + 自定义词库
                    .wordDeny(WordDenys.chains(WordDenySystem.getInstance(), () -> customWords))
                    .init();

            log.info("敏感词库加载完成，共 {} 个自定义词", customWords.size());
        } finally {
            LOCK.writeLock().unlock();
        }
    }

    /**
     * 从外部文件加载敏感词
     */
    private static List<String> loadWordsFromFile() {
        File file = new File(FileConstant.STATIC_ROOT_PATH, DEFAULT_WORDS_FILE);
        if (!file.exists()) {
            log.warn("未找到敏感词文件: {}", file.getAbsolutePath());
            return Collections.emptyList();
        }

        try (BufferedReader reader = Files.newBufferedReader(file.toPath(), StandardCharsets.UTF_8);
             Stream<String> lines = reader.lines()) {

            List<String> words = lines
                    .map(String::trim)
                    .filter(StrUtil::isNotBlank)
                    .toList();

            log.info("从外部文件加载敏感词 {} 个", words.size());
            return words;

        } catch (IOException e) {
            log.error("读取敏感词文件失败: {}", file.getAbsolutePath(), e);
            return Collections.emptyList();
        }
    }
}
